package pl.edu.mimuw.irs.core.model.analysis.dd;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import pl.edu.mimuw.irs.core.model.analysis.resources.ResourcePlace;
import pl.edu.mimuw.irs.core.model.design.net.Fragmentation;

public class PathNode {

	// *** Attributes

	private Fragmentation fragmentation;
	private ActivityWrapper activity;
	/*
	 * Owner is only in the root path node. As activity it is not stored in
	 * activity because activities are stored only in leaves, and whole DD
	 * mechanism bases on this assumption.
	 */
	private ActivityWrapper owner;
	private PathNode root;
	private PathNode parent;
	private List<PathNode> children;
	private int depth;
	private boolean deadEnd;
	private boolean started;
	private Boolean cachedValue;
	// Getters and setters;
	public Fragmentation getFragmentation() {
		return fragmentation;
	}
	public ActivityWrapper getActivity() {
		return activity;
	}
	public PathNode getRoot() {
		return root;
	}
	public void setRoot(PathNode root) {
		this.root = root;
		if (getParent() != null) {
			this.depth = getParent().getDepth() + 1;
		} else {
			this.depth = 0;
		}
		for (PathNode child : getChildren()) {
			child.setRoot(root);
		}
	}
	public PathNode getParent() {
		return parent;
	}
	public void setParent(PathNode parent) {
		this.parent = parent;
		if (parent == null) {
			this.depth = 0;
			setRoot(this);
		} else {
			parent.getChildren().add(this);
			setRoot(parent.getRoot());
		}
	}
	public List<PathNode> getChildren() {
		if (activity != null && activity.getDescendingPath() != null)
				return (activity.getDescendingPath().getChildren());
		if (children == null) {
			children = new LinkedList<PathNode>();
		}
		return children;
	}
	public int getDepth() {
		return depth;
	}
	public boolean isDeadEnd() {
		return deadEnd && activity == null;
	}
	public void setDeadEnd(boolean deadEnd) {
		this.deadEnd = deadEnd;
	}
	public boolean isStarted() {
		return started;
	}
	public void setStarted(boolean started) {
		this.started = started;
		if (getParent() != null) getParent().setStarted(started);
	}
	public ActivityWrapper getOwner() {
		return owner;
	}
	public void setOwner(ActivityWrapper owner) {
		this.owner = owner;
	}
	public Boolean getCachedValue() {
		return cachedValue;
	}
	public void clearCache() {
		cachedValue = null;
		if (parent != null) parent.clearCache();
		if (owner != null) owner.clearCache();
	}
	
	// *** Constructors
	
	public PathNode(PathNode parent, Fragmentation fragmentation, List<PathNode> children, ActivityWrapper activity) {
		this.fragmentation = fragmentation;
		this.children = children;
		this.activity = activity;
		setParent(parent);
	}
	
	public PathNode(PathNode parent, Fragmentation fragmentation, ActivityWrapper activity) {
		this(parent, fragmentation, null, activity);
	}
	
	public PathNode(PathNode parent, Fragmentation fragmentation) {
		this(parent, fragmentation, (ActivityWrapper)null);
	}

	public PathNode(PathNode parent, Fragmentation fragmentation, List<PathNode> children) {
		this(parent, fragmentation, children, null);
	}

	public PathNode(Fragmentation fragmentation, List<PathNode> children) {
		this(null, fragmentation, children, null);
	}
	
	public PathNode(Fragmentation fragmentation) {
		this(null, fragmentation);
	}
	
	// *** Methods
	
	@Override
	public String toString() {
		if (getActivity() == null) {
			if (deadEnd) {
				return "DeadEnd";
			} else {
				return "" + getFragmentation() + getChildren();
			}
		} else {
			return getActivity().toString();
		}
	}
	
	public Collection<? extends ResourcePlace> getDerivedResources() {
		if (owner != null) return owner.getDerivedResources();
		else if (parent != null) return parent.getDerivedResources();
		else return new HashSet<ResourcePlace>();
	}
}
